<?php

namespace App\V3\V3_1\Services;

use App\Exceptions\Exceptions;
use App\V3\V3_1\Models\LogInStorageModel;
use App\V3\V3_1\Models\LogOutStorageModel;
use App\V3\V3_1\Models\MaterielTypeModel;
use App\V3\V3_1\Models\ProductFillOrBalanceContentModel;
use App\V3\V3_1\Models\ProductFillOrBalanceModel;
use App\V3\V3_1\Models\ProductHistoryModel;
use App\V3\V3_1\Models\ProductOrderModel;
use App\V3\V3_1\Models\ProductSlaveContentModel;
use App\V3\V3_1\Models\ProductSlaveModel;
use App\V3\V3_1\Models\SellGoodsDetailModel;
use App\V3\V3_1\Models\SellModel;
use App\V3\V3_1\Models\SerialNumberModel;
use App\V3\V3_1\Models\StorageBatchModel;
use App\V3\V3_1\Models\StorageManageModel;
use App\V3\V3_1\Models\StorageModel;
use App\V3\V3_1\Models\StorageShelfLocationModel;
use App\V3\V3_1\Models\StorageShelfModel;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

class ProductService1
{
    public static function add(array $data)
    {
        DB::beginTransaction();

        try {
            //product_source:订单来源；0:普通生产订单;1:销售单;
            switch($data['product_source']) {
                case 0:
                    self::normalAdd($data);
                    break;
                case 1:
                    self::addFromSell($data);
                    break;
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch (Exception $e) {
            DB::rollBack();
            Log::debug('添加生产订单异常:'.var_export($data, true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    private static function addFromSell(array $data)
    {
        $sellInfo = SellModel::detail($data['product_source_id'])->toArray();

        if(empty($sellInfo)) {
            throw new Exception('无效销售单');
        }

        if($sellInfo['has_product_order']) {
            throw new Exception('销售单无法重复生成生产订单');
        }

        $taskContent = [];
        foreach($sellInfo['materiel_info'] as $value) {
            $typeInfo = MaterielTypeModel::where('id', $value['materiel_type_id'])->first();

            $taskContent[] = [
                'type_id' => $value['materiel_type_id'],
                'is_product_materiel' => $typeInfo['is_product_materiel'],
                'num' => $value['num']
            ];
        }

        $materielContent = json_decode($data['materiel_content'], true);

        $typeInfo = self::typeInfo($taskContent);//生产任务内容信息
        $contentInfo = self::contentInfo($materielContent, $data);//生产原料信息

        //比较生产任务和材料数量是否相符
        $checkMaterielInTask = self::checkMaterielInTask($typeInfo['task_info'], $contentInfo['content_info']);

        if($checkMaterielInTask) {
            $assisanData = [
                'product_no' => 'p'.self::createProductNo(),
                'total_num' => $typeInfo['num'],
                'product_source' => $data['product_source'],
                'relation_no' => $sellInfo['order_no'],
                'product_source_id' => $data['product_source_id'],
                'product_way' => $data['product_way'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'created_at' => time()
            ];

            $productOrderId = ProductOrderModel::insertGetId($assisanData);

            $slaveData = [];
            foreach($taskContent as $value) {
                $slaveData[] = [
                    'product_order_id' => $productOrderId,
                    'is_product_materiel' => $value['is_product_materiel'],
                    'type_id' => $value['type_id'],
                    'num' => $value['num'],
                    'created_at' => time()
                ];
            }

            ProductSlaveModel::insert($slaveData);

            $slaveContentData = [];
            foreach($contentInfo['content_data'] as $val) {
                $slaveContentData[] = [
                    'product_order_id' => $productOrderId,
                    'type_id' => $val['type_id'],
                    'storage_manage_id' => $val['storage_manage_id'],
//                    'batch_id' => empty($val['batch_id'])?0:$val['batch_id'],
                    'serial_id' => empty($val['serial_id'])?0:$val['serial_id'],
                    'product_source' => $data['product_source'],
                    'product_source_id' => $data['product_source_id'],
                    'num' => $val['num'],
                    'created_at' => $val['created_at']
                ];
            }

            ProductSlaveContentModel::insert($slaveContentData);
        }

        SellModel::where('id', $data['product_source_id'])->update(['has_product_order'=>1]);

        return true;
    }

    private static function normalAdd(array $data)
    {
        //参数验证
        $validator = Validator::make($data, [
            'task_content' =>'required|string',//生产任务
            'materiel_content' =>'required|string',//原料信息
        ],
            [
                'task_content.required' => '参数`生产任务`缺失',
                'materiel_content.required' => '参数`原料信息`缺失'
            ]
        );

        //参数错误响应
        if ($info = $validator->errors()->first()) {
            throw new Exception($info);
        }

        $taskContent = json_decode($data['task_content'], true);
        $materielContent = json_decode($data['materiel_content'], true);

        $taskNum = [];//商品所需数量

        $typeInfo = self::checkTypeInfo($taskContent);//生产任务内容信息
        $contentInfo = self::contentInfo($materielContent, $data);//生产原料信息

        //比较生产任务和材料数量是否相符
        $checkMaterielInTask = self::checkMaterielInTask($typeInfo['task_info'], $contentInfo['content_info']);

        if($checkMaterielInTask) {
            $assisanData = [
                'product_no' => 'p'.self::createProductNo(),
                'total_num' => $typeInfo['num'],
                'product_way' => $data['product_way'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'created_at' => time()
            ];

            $productOrderId = ProductOrderModel::insertGetId($assisanData);

            $slaveData = [];
            foreach($taskContent as $value) {
                $slaveData[] = [
                    'product_order_id' => $productOrderId,
                    'is_product_materiel' => $value['is_product_materiel'],
                    'type_id' => $value['type_id'],
                    'num' => $value['num'],
                    'created_at' => time()
                ];
            }

            ProductSlaveModel::insert($slaveData);

            $slaveContentData = [];
            foreach($contentInfo['content_data'] as $val) {
                $slaveContentData[] = [
                    'product_order_id' => $productOrderId,
                    'type_id' => $val['type_id'],
                    'storage_manage_id' => $val['storage_manage_id'],
//                    'batch_id' => $val['batch_id'],
                    'serial_id' => $val['serial_id'],
                    'num' => $val['num'],
                    'created_at' => $val['created_at']
                ];
            }

            ProductSlaveContentModel::insert($slaveContentData);
        }

        return true;
    }

    //验证生产任务信息
    private static function checkTypeInfo($taskContent)
    {
        $taskNum = [];
        $num = 0;
        foreach($taskContent as $value) {
            $materielInfo = MaterielTypeModel::getInfo($value['type_id']);

            if(empty($materielInfo)) {
                throw new Exceptions('商品:'.$materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'不存在');
            }

            //验证是否为套餐
            if($materielInfo['is_product_materiel']) {
                if(empty($materielInfo['content'])) {
                    throw new Exception('无法生产空白套餐');
                }

                MaterielTypeModel::where('id', $materielInfo['id'])->update(['product_use_tag' => 1]);

                foreach($materielInfo['content'] as $val) {
                    if(array_key_exists($val['id'], $taskNum)) {
                        $taskNum[$val['type_id']] += $val['num'] * $value['num'];
                    }
                    else {
                        $taskNum[$val['type_id']] = $val['num'] * $value['num'];
                    }
                }
            }
            else {
                if(array_key_exists($materielInfo['id'], $taskNum)) {
                    $taskNum[$materielInfo['id']] += $value['num'];
                }
                else {
                    $taskNum[$materielInfo['id']] = $value['num'];
                }
            }

            $num += $value['num'];
        }

        return ['task_num' => $num, 'task_materiel_num' => $taskNum];
    }

    //生产原料信息
    private static function contentInfo($materielContent, $data)
    {
        $contentInfo = [];
        $storageInfo = [];
        foreach($materielContent as $value) {
            $materielInfo = MaterielTypeModel::getInfo($value['type_id']);

            $num = 0;
            if($materielInfo['is_use_serial']) {
                if(empty(array_filter($value['serial_info']))) {
                    throw new Exception('商品:'.$materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'已开启序列号，请选择序列号');
                }

                foreach($value['serial_info'] as $serialVal) {
                    $num += $serialVal['num'];

                    $serialInfo = SerialNumberModel::where('id', $serialVal['serial_id'])->first();
                    $storageManageInfo = StorageManageModel::where('id', $serialVal['storage_manage_id'])->first();

                    if(empty($storageManageInfo)) {
                        throw new Exception('无效库存，请重试');
                    }

                    if($serialVal['num'] > $storageManageInfo['virtual_storage_num']) {
                        throw new Exception('序列号：'.$serialInfo['serial_no'].'对应的可用库存数量不足，当前所需数量为：'.$serialVal['num'].',当前可用库存为:'.$storageManageInfo['in_storage_num']);
                    }

                    $storageInfo[] = [
                        'type_id' => $storageManageInfo['type_id'],
                        'storage_manage_id' => $storageManageInfo['id'],
//                        'batch_id' => 0,
                        'serial_id' => $serialVal['serial_id'],
                        'num' => $serialVal['num'],
                        'created_at' => time(),
                    ];
                }
            }
            else {
//                if($data['use_batch']) {
//                    if(empty(array_filter($value['batch_info']))) {
//                        throw new Exception('系统设置中已开启序列号，请选择序列号');
//                    }
//
//                    foreach($value['batch_info'] as $batchVal) {
//                        $num += $batchVal['num'];
//
//                        $batchInfo = StorageBatchModel::where('id', $batchVal['batch_id'])->first();
//                        $storageManageInfo = StorageManageModel::where('id', $batchVal['storage_manage_id'])->first();
//
//                        if(empty($storageManageInfo)) {
//                            throw new Exception('无效库存，请重试');
//                        }
//
//                        if($batchInfo['batch_left_num'] > $storageManageInfo['in_storage_num']) {
//                            throw new Exception('序列号：'.$batchInfo['batch_no'].'对应的库存数量不足，当前所需数量为：'.$batchInfo['batch_left_num'].',当前实时库存为:'.$storageManageInfo['in_storage_num']);
//                        }
//
//                        $storageInfo[] = [
//                            'type_id' => $storageManageInfo['type_id'],
//                            'storage_manage_id' => $storageManageInfo['id'],
//                            'batch_id' => $batchVal['batch_id'],
//                            'serial_id' => 0,
//                            'num' => $batchVal['num'],
//                            'created_at' => time(),
//                        ];
//                    }
//                }
//                else {
//                    $num += $value['num'];
//
//                    $storageManageInfo = StorageManageModel::where('id', $value['storage_manage_id'])->first();
//
//                    if(empty($storageManageInfo)) {
//                        throw new Exception('无效库存，请重试');
//                    }
//
//                    $serialInfo = SerialNumberModel::where('storage_manage_id', $value['storage_manage_id'])->where('status', 1)->first();
//                    $batchInfo = StorageBatchModel::where([
//                        'storage_manage_id' => $value['storage_manage_id']
//                    ])
//                        ->orderBy('batch_left_num', 'desc')->first();
//
//                    $storageInfo[] = [
//                        'type_id' => $value['type_id'],
//                        'storage_manage_id' => $value['storage_manage_id'],
//                        'batch_id' => empty($batchInfo)?0:$batchInfo['id'],
//                        'serial_id' => empty($serialInfo)?0:$serialInfo['id'],
//                        'num' => $value['num'],
//                        'created_at' => time(),
//                    ];
//                }
                $num += $value['num'];

                $storageManageInfo = StorageManageModel::where('id', $value['storage_manage_id'])->first();

                if(empty($storageManageInfo)) {
                    throw new Exception('无效库存，请重试');
                }

                $serialInfo = SerialNumberModel::where('storage_manage_id', $value['storage_manage_id'])->where('status', 1)->first();
                $batchInfo = StorageBatchModel::where([
                    'storage_manage_id' => $value['storage_manage_id']
                ])
                    ->orderBy('batch_left_num', 'desc')->first();

                $storageInfo[] = [
                    'type_id' => $value['type_id'],
                    'storage_manage_id' => $value['storage_manage_id'],
//                    'batch_id' => empty($batchInfo)?0:$batchInfo['id'],
                    'serial_id' => empty($serialInfo)?0:$serialInfo['id'],
                    'num' => $value['num'],
                    'created_at' => time(),
                ];
            }

            if(array_key_exists($value['type_id'], $contentInfo)) {
                $contentInfo[$value['type_id']] += $num;
            }
            else {
                $contentInfo[$value['type_id']] = $num;
            }
        }

        return ['content_data' => $storageInfo, 'content_info' => $contentInfo];
    }

    //比较生产任务和材料数量是否相符
    private static function checkMaterielInTask(array $typeInfo, array $contentInfo)
    {
        if(count($typeInfo) != count($contentInfo)) {
            throw new Exception('生产原料与生产任务所需的原料不匹配,原因：部分原料缺失');
        }

        foreach($typeInfo as $key => $value) {
            foreach($contentInfo as $k => $val) {
                if($key == $k) {
                    if($value > $val) {
                        throw new Exception('选取的原料数量不足以完成生产');
                    }
//                    else if($value < $val) {
//                        throw new Exception('选取的原料数量，已超出生产所需数量');
//                    }
                }
            }
        }

        return true;
    }

    //创建采购单号
    private static function createProductNo()
    {
        list($t1, $t2) = explode(' ', microtime());
        $str =(float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
        $millisecond = substr($str,10,13);
        $date = date("YmdHis").$millisecond.mt_rand(100000,999999);

        return $date;
    }

    //详细
    public static function detail($id, $mainId)
    {
        return ProductOrderModel::detail($id, $mainId);
    }

    public static function del($id, $mainId)
    {
        $info = ProductOrderModel::detail($id, $mainId);

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效的目标单据，请刷新后重试', 'data' => ''];
        }

        if($info['product_status']) {
            return ['code' => 1, 'msg' => '订单正在生产中，无法删除，请重试', 'data' => ''];
        }

        $info->delete_flag = 1;
        $info->save();

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    //生产订单列表
    public static function list(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        if($data['search_type'] != 0) {
            switch($data['search_type']) {
                case 1://商品名
                    $result = self::searchByMaterielName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 2://规格名
                    $result = self::searchByTypeName($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 3://商品编号
                    $result = self::searchByMaterielNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 4://内部单号
                    $result = self::searchByOrderNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 5://关联单号
                    $result = self::searchByRelationNo($data, $condition, $keyword, $startTime, $endTime);
                    break;
                case 6://操作人
                    $result = self::searchByOperator($data, $condition, $keyword, $startTime, $endTime);
                    break;
            }
        }
        else {
            //全部
            $result = self::searchAll($data, $condition, $keyword, $startTime, $endTime);
        }

        return $result;
    }

    //生产订单列表-商品名
    private static function searchByMaterielName(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByMaterielNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByMaterielNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    private static function commonSearch(array $orderId, array $data)
    {
        return ProductOrderModel::list($orderId, $data);
    }

    //生产订单列表-规格名
    private static function searchByTypeName(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByTypeNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByTypeNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-商品编号
    private static function searchByMaterielNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id
        $slaveGetOrderIdInfo = ProductOrderModel::searchByMaterielNoInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id
        $slaveContentGetOrderIdInfo = ProductOrderModel::searchByMaterielNoInSlaveContent($data, $condition, $keyword, $startTime, $endTime);

        //组装生产订单主id
        $orderId = self::assianOrderId($slaveGetOrderIdInfo, $slaveContentGetOrderIdInfo);

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-内部单号
    private static function searchByOrderNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByProductNoInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-关联单号
    private static function searchByRelationNo(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByRelationNoInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-操作人
    private static function searchByOperator(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从主单获取id
        $orderIdInfo = ProductOrderModel::searchByOperatorInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-全部
    private static function searchAll(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        if(empty($keyword)) {
            //无关键词
            $result = self::searchAllWithOutKeyword($data, $condition, $startTime, $endTime);
        }
        else {
            //有关键词
            $result = self::searchAllWithKeyword($data, $condition, $keyword, $startTime, $endTime);
        }

        return $result;
    }

    //生产订单列表-全部-无关键词
    private static function searchAllWithOutKeyword(array $data, array $condition, $startTime, $endTime)
    {
        $orderIdInfo = ProductOrderModel::searchAllWithOutKeyword($data, $condition, $startTime, $endTime);

        $orderId = [];
        foreach($orderIdInfo as $value) {
            $orderId[] = $value['id'];
        }

        return self::commonSearch($orderId, $data);
    }

    //生产订单列表-全部-有关键词
    private static function searchAllWithKeyword(array $data, array $condition, $keyword, $startTime, $endTime)
    {
        //从子单获取主单id-商品名
        $slaveMaterielInfo = ProductOrderModel::searchByMaterielNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-商品名
        $slaveContentMaterielInfo = ProductOrderModel::searchByMaterielNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从子单获取主单id-规格名
        $slaveTypeInfo = ProductOrderModel::searchByTypeNameInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-规格名
        $slaveContentTypeInfo = ProductOrderModel::searchByTypeNameInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从子单获取主单id-商品编号
        $slaveMaterielNoInfo = ProductOrderModel::searchByMaterielNoInSlave($data, $condition, $keyword, $startTime, $endTime);
        //从子单内容表获取主单id-商品编号
        $slaveContentMaterielNoInfo = ProductOrderModel::searchByMaterielNoInSlaveContent($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id-生产单编号
        $productNoInfo = ProductOrderModel::searchByProductNoInOrder($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id-关联单号
        $relationNoInfo = ProductOrderModel::searchByRelationNoInOrder($data, $condition, $keyword, $startTime, $endTime);
        //从主单获取id
        $operatorInfo = ProductOrderModel::searchByOperatorInOrder($data, $condition, $keyword, $startTime, $endTime);

        $orderId = self::assianOrderId(
            $slaveMaterielInfo,
            $slaveContentMaterielInfo,
            $slaveTypeInfo,
            $slaveContentTypeInfo,
            $slaveMaterielNoInfo,
            $slaveContentMaterielNoInfo,
            $productNoInfo,
            $relationNoInfo,
            $operatorInfo,
        );

        return self::commonSearch($orderId, $data);
    }

    //组装id
    private static function assianOrderId($arr, $arr1, $arr2 = [], $arr3 = [], $arr4 = [], $arr5 = [], $arr6 = [], $arr7 = [], $arr8 = [])
    {
        $orderId = [];
        if(!empty($arr)) {
            foreach($arr as $value) {
                if(!in_array($value['id'], $orderId)) {
                    array_push($orderId, $value['id']);
                }
            }
        }

        if(!empty($arr1)) {
            foreach ($arr1 as $val) {
                if(!in_array($val['id'], $orderId)) {
                    array_push($orderId, $val['id']);
                }
            }
        }

        if(!empty($arr2)) {
            foreach($arr2 as $value) {
                if(!in_array($value['id'], $orderId)) {
                    array_push($orderId, $value['id']);
                }
            }
        }

        if(!empty($arr3)) {
            foreach ($arr3 as $val) {
                if(!in_array($val['id'], $orderId)) {
                    array_push($orderId, $val['id']);
                }
            }
        }

        if(!empty($arr4)) {
            foreach($arr4 as $v) {
                if(!in_array($v['id'], $orderId)) {
                    array_push($orderId, $v['id']);
                }
            }
        }

        if(!empty($arr5)) {
            foreach ($arr5 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr6)) {
            foreach ($arr6 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr7)) {
            foreach ($arr7 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        if(!empty($arr8)) {
            foreach ($arr8 as $v1) {
                if(!in_array($v1['id'], $orderId)) {
                    array_push($orderId, $v1['id']);
                }
            }
        }

        return $orderId;
    }

    //撤销
    public static function cancel($data)
    {
        $info = ProductOrderModel::detail($data['id'], $data['main_id']);

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效生产订单，请重试', 'data' => ''];
        }

        if($info['product_status'] != 0) {
            return ['code' => 1, 'msg' => '仅新生产订单可撤销', 'data' => ''];
        }

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '无法重复撤销', 'data' => ''];
        }

        $info->is_cancel = 1;
        $info->save();

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    //重新下单
    public static function again(array $data)
    {
        $info = ProductOrderModel::detail($data['id'], $data['main_id'])->toArray();

        if(empty($info)) {
            return ['code' => 1, 'msg' => '无效生产订单，请重试', 'data' => ''];
        }

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '目标订单已撤销，无法下单', 'data' => ''];
        }

        if($info['product_source'] != 0) {
            return ['code' => 1, 'msg' => '仅普通订单可重新下单', 'data' => ''];
        }

        $arr = [
            'product_no' => 'p'.self::createProductNo(),
            'product_status' => 0,
            'product_source' => $info['product_source'],
            'product_source_id' => $info['product_source_id'],
            'total_num' => $info['total_num'],
            'relation_no' => $info['relation_no'],
            'product_way' => $info['product_way'],
            'is_cancel' => 0,
            'main_id' => $info['main_id'],
            'user_id' => $info['user_id'],
            'created_at' => time()
        ];

        DB::beginTransaction();

        try {
            $orderId = ProductOrderModel::insertGetId($arr);

            $slaveData = [];
            foreach($info['slave_info'] as $value) {
                $slaveData[] = [
                    'product_order_id' => $orderId,
                    'is_product_materiel' => $value['is_product_materiel'],
                    'type_id' => $value['type_id'],
                    'num' => $value['num'],
                    'created_at' => time()
                ];
            }

            ProductSlaveModel::insert($slaveData);

            $slaveContentData = [];
            foreach($info['slave_content'] as $val) {
                $slaveContentData[] = [
                    'product_order_id' => $orderId,
                    'type_id' => $val['type_id'],
                    'storage_manage_id' => $val['storage_manage_id'],
//                    'batch_id' => empty($val['batch_id'])?0:$val['batch_id'],
                    'serial_id' => empty($val['serial_id'])?0:$val['serial_id'],
                    'product_source' => $val['product_source'],
                    'product_source_id' => $val['product_source_id'],
                    'num' => $val['num'],
                    'created_at' => time()
                ];
            }

            ProductSlaveContentModel::insert($slaveContentData);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('生产订单重新下单异常:'.var_export($e->getMessage()));
            return ['code' => 1, 'msg' => '生产订单重新下单异常', 'data' => ''];
        }
    }

    //生产订单完成
    public static function finished(array $data)
    {
        $mainOrderInfo = ProductOrderModel::getMainOrderInfo($data['id']);

//        if($mainOrderInfo['product_status'] == 2) {
//            return ['code' => 1, 'msg' => '目标生产订单已生产完成，无法继续生产', 'data' => ''];
//        }
//
//        if($mainOrderInfo['is_cancel']) {
//            return ['code' => 1, 'msg' => '目标生产订单已撤销，无法继续生产', 'data' => ''];
//        }

        $data['product_time'] = empty($data['product_time'])?date('Y-m-d H:i:s'):$data['product_time'];

        DB::beginTransaction();

        try {
            $content = json_decode($data['product_info'], true);

            if(empty($content)) {
                throw new Exception('所需生产的任务内容不能为空');
            }

            $slaveData = [];
            $num = 0;
            $history = [];
            foreach($content as $value) {
                //获取任务信息
                $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();
                $typeInfo = MaterielTypeModel::where('id', $slaveInfo['type_id'])->first();

                if($value['num'] > ($slaveInfo['num'] - $slaveInfo['finished_num'])) {
                    throw new Exception('您输入的数量超出商品'.$typeInfo['materiel_name'].'-'.$typeInfo['materiel_name'].'剩余可生产的任务数');
                }

                //生产任务完成前数据组装
                $slaveData[] = [
                    'id' => $value['id'],
                    'finished_num' => $slaveInfo['finished_num'] + $value['num']
                ];

                $num += $value['num'];

                $history[] = [
                    'product_order_id' => $data['id'],
                    'product_slave_id' => $value['id'],
                    'num' => $value['num'],
                    'before_product_num' => $slaveInfo['finished_num'],
                    'rest_num' => $slaveInfo['num'] - ($slaveInfo['finished_num'] + $value['num']),
                    'user_id' => $data['user_id'],
                    'main_id' => $data['main_id'],
                    'product_source' => $mainOrderInfo['product_source'],
                    'product_source_id' => $mainOrderInfo['product_source_id'],
                    'product_time' => strtotime($data['product_time']),
                    'created_at' => time()
                ];
            }

            if($num != 0) {
                //批量修改生产任务已完成数
                if (!empty($slaveData)) {
                    batch()->update(new ProductSlaveModel, $slaveData, 'id');
                }

                $mainOrderInfo->finished_num += $num;

                if ($mainOrderInfo->total_num == $mainOrderInfo->finished_num) {
                    $mainOrderInfo->product_status = 2;
                } else {
                    $mainOrderInfo->product_status = 1;
                }

                $mainOrderInfo->save();

                if (!empty($history)) {
                    ProductHistoryModel::insert($history);
                }

                //生产订单中生产任务全部完成时出库
                if($mainOrderInfo->product_status == 2) {
                    self::slaveContentOut($data, $mainOrderInfo);
                }
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('生产订单生产异常'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //补足或还库
    public static function fillOrBalance(array $data)
    {
        $unionCode = 'fb'.self::createProductNo();
        $taskContent = json_decode($data['task_content'], true);
        $materielContent = json_decode($data['materiel_content'], true);

        $productInfo = ProductOrderModel::detail($data['id'], $data['main_id']);

        if($productInfo['product_status'] != 2) {
            return ['code' => 1, 'msg' => '生产订单已完成后才可以补足或还库', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            if(!$data['type']) {//补足
                self::fill($data, $taskContent, $materielContent, $unionCode);
            }
            else {//还库
                self::balance($data, $taskContent, $materielContent, $unionCode);
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('补足或还库异常'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //补足
    private static function fill(array $data, $taskContent, $materielContent, $unionCode)
    {
        $taskNum = [];//商品所需数量

        $typeInfo = self::typeInfo($taskContent);//生产任务内容信息
        $contentInfo = self::contentInfo($materielContent, $data);//生产原料信息

        //比较生产任务和材料数量是否相符
        $checkMaterielInTask = self::checkMaterielInTask($typeInfo['task_info'], $contentInfo['content_info']);

        if($checkMaterielInTask) {
            $task = [];
            foreach($taskContent as $value) {
                $task[] = [
                    'type' => $data['type'],
                    'product_order_id' => $data['id'],
                    'type_id' => $value['type_id'],
                    'is_product_materiel' => $value['is_product_materiel'],
                    'num' => $value['num'],
                    'union_code' => $unionCode,
                    'created_at' => time()
                ];
            }

            $content = [];
            foreach($contentInfo['content_data'] as $val) {
                $content[] = [
                    'product_order_id' => $data['id'],
                    'union_code' => $unionCode,
                    'type_id' => $val['type_id'],
                    'storage_manage_id' => $val['storage_manage_id'],
                    'serial_id' => $val['serial_id'],
                    'num' => $val['num'],
                    'created_at' => time()
                ];
            }

            ProductFillOrBalanceModel::insert($task);
            ProductFillOrBalanceContentModel::insert($content);

            $serialId = [];
            $storageManageData = [];
            $logData = [];
            //库存操作前准备
            foreach($content as $value) {
                $serialInfos = [];
                if($value['serial_id'] != 0) {
                    if(empty(SerialNumberModel::find($value['serial_id']))) {
                        throw new Exception('序列号不存在或已被使用');
                    }

                    $serialId[] = [
                        'id' => $value['serial_id'],
                        'status' => 0
                    ];

                    //套件信息
                    $serialInfos = SerialNumberModel::where('id', $value['serial_id'])->first();
                }

                $arr['id'] = $value['storage_manage_id'];
                $storageManageInfo = StorageManageModel::detail($arr);

                if($value['num'] > $storageManageInfo['in_storage_num']) {
                    throw new Exception($storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'库存数不足，当前库存为'.$storageManageInfo['in_storage_num']);
                }

                $storageManageData[] = [
                    'id' => $value['storage_manage_id'],
                    'in_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                    'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $value['num'],
                ];

                $logData[] = [
                    'type' => 0,
                    'storage_id' => $storageManageInfo['storage_id'],
                    'storage_name' => $storageManageInfo['storage_name'],
                    'storage_address' => $storageManageInfo['storage_address'],
                    'curr_storage_manage_id' => $storageManageInfo['id'],
                    'materiel_class_id' => $storageManageInfo['s_class_id'],
                    'materiel_class_name' => $storageManageInfo['s_class_name'],
                    'materiel_class_no' => $storageManageInfo['s_class_no'],
                    'materiel_type_id' => $storageManageInfo['type_id'],
                    'materiel_name' => $storageManageInfo['materiel_name'],
                    'type_name' => $storageManageInfo['type_name'],
                    'materiel_no' => $storageManageInfo['materiel_no'],
                    'relation_code' => $unionCode,
                    'operate_num' => $value['num'],
                    'serial_number' => empty($serialInfos)?'':$serialInfos['serial_no'],
                    'last_storage_num' => $storageManageInfo['in_storage_num'],
                    'next_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                    'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
                    'fact_out_time' => strtotime(date('Y-m-d')),
                    'all_id_type' => 4,
                    'all_id' => $data['id'],
                    'user_id' => $data['user_id'],
                    'main_id' => $data['main_id'],
                    'out_storage_time' => time(),
                    'created_at' => time(),
                    'shelf_id' => $storageManageInfo['shelf_id'],
                    'location_id' => $storageManageInfo['location_id'],
                ];

                MessageService::sendAlertSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $storageManageInfo['alert_num'],
                    $data['main_id'],
                    $storageManageInfo['storage_id'],
                    $storageManageInfo['storage_name'],
                    $value['num']
                );

                MessageService::sendShortSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $data['main_id'],
                    $storageManageInfo['storage_name'],
                    $storageManageInfo['storage_id'],
                );

                MessageService::sendOutSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $storageManageInfo['storage_name'],
                    $value['num'],
                    $data['user_id'],
                    $storageManageInfo['storage_id'],
                    $storageManageInfo['alert_num'],
                );
            }

            //序列号入库-更新已使用序列号状态
            if(!empty($serialId)) {
                batch()->update(new SerialNumberModel, $serialId, 'id');
            }

            //更新库存-扣除库存
            if(!empty($storageManageData)) {
                batch()->update(new StorageManageModel, $storageManageData, 'id');
            }

            LogOutStorageModel::insert($logData);
        }

        return true;
    }

    //还库
    private static function balance(array $data, $taskContent, $materielContent, $unionCode)
    {
        $task = [];
        foreach($taskContent as $value) {
            $task[] = [
                'type' => $data['type'],
                'product_order_id' => $data['id'],
                'type_id' => $value['type_id'],
                'is_product_materiel' => $value['is_product_materiel'],
                'num' => $value['num'],
                'union_code' => $unionCode,
                'created_at' => time()
            ];
        }

        $content = [];
        $storageInfo = [];
        $serialId = [];
        foreach($materielContent as $val) {
            $materielInfo = MaterielTypeModel::getInfo($val['type_id']);

            if($materielInfo['is_use_serial']) {
                if (empty(array_filter($val['serial_info']))) {
                    throw new Exception('商品:' . $materielInfo['materiel_name'] . '-' . $materielInfo['type_name'] . '已开启序列号，请选择序列号');
                }

                $num = 0;
                foreach($val['serial_info'] as $serialVal) {
                    $serialInfo = SerialNumberModel::where('id', $serialVal['serial_id'])->first();

                    if($serialInfo['status']) {
                        throw new Exception('序列号:'.$serialInfo['serial_no'].'未被使用，无法还库');
                    }
                    $num += $serialVal['num'];

                    $storageInfo[] = [
                        'type_id' => $val['type_id'],
                        'product_order_id' => $data['id'],
                        'storage_manage_id' => $serialInfo['storage_manage_id'],
                        'serial_id' => $serialInfo['id'],
                        'num' => 1,
                        'created_at' => time(),
                    ];
                }

                if($val['num'] > $num) {
                    throw new Exception('商品:' . $materielInfo['materiel_name'].'-'.$materielInfo['type_name'].'所选取的序列号数量与还库数量不符');
                }
            }
            else {
                $storageInfo[] = [
                    'type_id' => $val['type_id'],
                    'product_order_id' => $data['id'],
                    'storage_manage_id' => $val['storage_manage_id'],
                    'serial_id' => 0,
                    'num' => $val['num'],
                    'created_at' => time(),
                ];
            }
        }

        ProductFillOrBalanceModel::insert($task);
        ProductFillOrBalanceContentModel::insert($storageInfo);

        $serialId = [];
        $storageManageData = [];
        $logData = [];
        foreach($storageInfo as $value) {
            $serialInfos = [];
            if($value['serial_id'] != 0) {
                $serialId[] = [
                    'id' => $value['serial_id'],
                    'status' => 1
                ];

                $serialInfos = SerialNumberModel::where('id', $value['serial_id'])->first();
            }

            $arr['id'] = $value['storage_manage_id'];
            $storageManageInfo = StorageManageModel::detail($arr);

            $storageManageData[] = [
                'id' => $value['storage_manage_id'],
                'in_storage_num' => $storageManageInfo['in_storage_num'] + $value['num'],
                'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] + $value['num'],
            ];

            $logData[] = [
                'type' => 0,
                'curr_storage_manage_id' => $storageManageInfo['id'],
                'storage_id' => $storageManageInfo['storage_id'],
                'storage_name' => $storageManageInfo['storage_name'],
                'storage_address' => $storageManageInfo['storage_address'],
                'materiel_class_id' => $storageManageInfo['s_class_id'],
                'materiel_class_name' => $storageManageInfo['s_class_name'],
                'materiel_class_no' => $storageManageInfo['s_class_no'],
                'materiel_type_id' => $storageManageInfo['type_id'],
                'materiel_name' => $storageManageInfo['materiel_name'],
                'type_name' => $storageManageInfo['type_name'],
                'materiel_no' => $storageManageInfo['materiel_no'],
                'purchase_no' => $unionCode,
                'operate_num' => $value['num'],
                'last_storage_num' => $storageManageInfo['in_storage_num'],
                'next_storage_num' => $storageManageInfo['in_storage_num'] + $value['num'],
                'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
                'serial_number' => empty($serialInfos)?'':$serialInfos['serial_no'],
                'all_id_type' => 5,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'in_storage_time' => time(),
                'created_at' => time(),
                'shelf_id' => $storageManageInfo['shelf_id'],
                'location_id' => $storageManageInfo['location_id'],
            ];

            MessageService::sendInSms(
                '',
                $storageManageInfo['materiel_name'],
                $storageManageInfo['type_name'],
                $storageManageInfo['storage_id'],
                $storageManageInfo['storage_name'],
                $data['user_id'],
                $value['num'],
                $storageManageInfo['in_storage_num'] + $value['num']
            );
        }

        //序列号入库-更新已使用序列号状态
        if(!empty($serialId)) {
            batch()->update(new SerialNumberModel, $serialId, 'id');
        }

        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        LogInStorageModel::insert($logData);

        return true;
    }

    //生产订单生产任务全部完成时，对生产原料出库
    private static function slaveContentOut(array $data)
    {
        $slaveContent = ProductSlaveContentModel::where('product_order_id', $data['id'])->get()->toArray();

        if(empty($slaveContent)) {
            throw new Exception('生产订单异常:生产订单无生产原料');
        }

        $serialId = [];
        $storageManageData = [];
        foreach($slaveContent as $value) {
            if($value['serial_id'] != 0) {
                $serialInfo = SerialNumberModel::where('id', $value['serial_id'])->first();

                if($serialInfo['status'] == 0) {
                    throw new Exception('序列号:'.$serialInfo['serial_no'].'已被使用，无法用户生产');
                }

                $serialId[] = $value['serial_id'];
            }

            $arr['id'] = $value['storage_manage_id'];
            $storageManageInfo = StorageManageModel::detail($arr);

            if($value['num'] > $storageManageInfo['in_storage_num']) {
                throw new Exception('库存商品:'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'库存数量不足，当前剩余数量');
            }

            $storageManageData[] = [
                'id' => $value['storage_manage_id'],
                'in_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $value['num'],
            ];

            $logData[] = [
                'type' => 0,
                'storage_id' => $storageManageInfo['storage_id'],
                'storage_name' => $storageManageInfo['storage_name'],
                'storage_address' => $storageManageInfo['storage_address'],
                'curr_storage_manage_id' => $storageManageInfo['id'],
                'materiel_class_id' => $storageManageInfo['s_class_id'],
                'materiel_class_name' => $storageManageInfo['s_class_name'],
                'materiel_class_no' => $storageManageInfo['s_class_no'],
                'materiel_type_id' => $storageManageInfo['type_id'],
                'materiel_name' => $storageManageInfo['materiel_name'],
                'type_name' => $storageManageInfo['type_name'],
                'materiel_no' => $storageManageInfo['materiel_no'],
                'relation_code' => '',
                'operate_num' => $value['num'],
                'serial_number' => empty($serialInfos)?'':$serialInfos['serial_no'],
                'last_storage_num' => $storageManageInfo['in_storage_num'],
                'next_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
                'fact_out_time' => strtotime(date('Y-m-d')),
                'all_id_type' => 3,
                'all_id' => $data['id'],
                'user_id' => $data['user_id'],
                'main_id' => $data['main_id'],
                'out_storage_time' => time(),
                'created_at' => time(),
                'shelf_id' => $storageManageInfo['shelf_id'],
                'location_id' => $storageManageInfo['location_id'],
            ];

            MessageService::sendAlertSms(
                $storageManageInfo['materiel_name'],
                $storageManageInfo['type_name'],
                $storageManageInfo['in_storage_num'],
                $storageManageInfo['alert_num'],
                $data['main_id'],
                $storageManageInfo['storage_id'],
                $storageManageInfo['storage_name'],
                $value['num']
            );

            MessageService::sendShortSms(
                $storageManageInfo['materiel_name'],
                $storageManageInfo['type_name'],
                $storageManageInfo['in_storage_num'],
                $data['main_id'],
                $storageManageInfo['storage_name'],
                $storageManageInfo['storage_id'],
            );

            MessageService::sendOutSms(
                $storageManageInfo['materiel_name'],
                $storageManageInfo['type_name'],
                $storageManageInfo['in_storage_num'],
                $storageManageInfo['storage_name'],
                $value['num'],
                $data['user_id'],
                $storageManageInfo['storage_id'],
                $storageManageInfo['alert_num'],
            );
        }

        //序列号入库-更新已使用序列号状态
        if(!empty($serialId)) {
            batch()->update(new SerialNumberModel, $serialId, 'id');
        }

        if(!empty($storageManageData)) {
            batch()->update(new StorageManageModel, $storageManageData, 'id');
        }

        LogInStorageModel::insert($logData);

        return true;
    }

    //生产订单出入库
    public static function inOrOut(array $data)
    {
        $productInfo = ProductOrderModel::getMainOrderInfo($data['id'], $data['main_id']);

        if($productInfo['product_status'] != 2) {
            return ['code' => 1, 'msg' => '生产订单已完成后才可以出入库或套件返仓', 'data' => ''];
        }

        //验证每次入库是否与初次入库类型相符，初次入库后，固定后续每次入库的操作方式
        if($productInfo['in_storage_type'] != 0) {
            if(in_array($data['type'], [0,1])) {
                if($productInfo['in_storage_type'] != $data['type']) {
                    if($productInfo['in_storage_type'] == 1) {
                        return ['code' => 1, 'msg' => '当前入库类型与初次入库类型不符', 'data' => ''];
                    }
                }
            }
        }

        if($productInfo['storage_operate_status'] == 2) {
            return ['code' => 1, 'msg' => '当前单据的出入库操作已完成，无法再次操作', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            switch($data['type']) {
                case 0://整件入库
                    self::fullInStorage($data, $productInfo);
                    break;
                case 1://套件返仓
                    self::piecesInStorage($data, $productInfo);
                    break;
                case 2://出库
                    self::productOutStorage($data, $productInfo);
                    break;
            }

            DB::commit();

            if(in_array($data['type'], [0,2])) {
                $checkSlave = ProductSlaveModel::where('product_order_id', $data['id'])
                    ->whereRaw('num > storage_operate_num')
                    ->first();

                $status = 1;
                if(!empty($checkSlave)) {
                    $status = 1;
                }
                else {
                    $status = 2;
                }

                //同步销售单状态
                if($data['type'] == 2) {
                    SellModel::where('id', $productInfo['product_source_id'])->update(['out_status' => $status]);
                }

                $productInfo->storage_operate_status = $status;
                $productInfo->save();
            }
            else if($data['type'] == 1) {
                $checkSlave = ProductSlaveContentModel::where('product_order_id', $data['id'])
                    ->whereRaw('num > storage_operate_num')
                    ->first();

                if(!empty($checkSlave)) {
                    $productInfo->storage_operate_status = 1;
                }
                else {
                    $productInfo->storage_operate_status = 2;
                }

                $productInfo->save();
            }

            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            Log::debug('生产订单出入库异常'.var_export($e->getMessage(), true));
            DB::rollBack();
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    //整件入库
    private static function fullInStorage(array $data, $productInfo)
    {
        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'main_id' => $data['main_id'],
            'delete_flag' => 0
        ])->first();

        if(empty($storageInfo)) {
            return ['code' => 1, 'msg' => '仓库不存在', 'data' => ''];
        }

        if($data['use_shelf']) {
            if($data['location_id'] == 0) {
                throw new Exception('设置中已开启货架，请选择货架库位后重试');
            }

            $shelfId = $data['shelf_id'];
            $locationId = $data['location_id'];
        }
        else {
            $shelfInfo = StorageShelfModel::where('storage_id', $data['storage_id'])->where('shelf_type', 1)->first();
            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])->first();

            $shelfId = $shelfInfo['id'];
            $locationId = $locationInfo['id'];
        }

        if(empty($data['task_content'])) {
            throw new Exception('请选择要入库的生产任务');
        }

        $taskContent = json_decode($data['task_content'], true);

        $existStorageData = [];//已存在的库存信息
        $logData = [];//日志信息
        $serialData = [];//序列号信息
        $slaveData = [];//变更入库的生产任务数
        foreach($taskContent as $value) {
            $slaveInfo = ProductSlaveModel::where('id', $value['id'])->first();

            $slaveData[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num'],
            ];

            if($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可入库数量,当前可入库数量为'.($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }
            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            $checkStorageManageInfo = StorageManageModel::getInfos([
                'type_id' => $value['type_id'],
                'storage_id' => $data['storage_id'],
                'main_id' => $data['main_id'],
                'shelf_id' => $shelfId,
                'location_id' => $locationId
            ]);

            //商品是否开启序列号
            if($materielTypeInfo['is_use_serial']) {
                if(empty($value['serial_info'])) {
                    throw new Exception('请填写序列号');
                }

                $serialInfo = explode(',', $value['serial_info']);

                //验证本次入库填写的序列号数量是否与入库数量相符
                if($value['num'] > count($serialInfo)) {
                    throw new Exception('您所填写的序列号数量与要入库的商品数不符，请重新填写');
                }

                if(empty($checkStorageManageInfo)) {
                    $storageManageId = StorageManageModel::insertGetId([
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'in_storage_num' => $value['num'],
                        'virtual_storage_num' => $value['num'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ]);

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $storageManageId,
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => 0,
                        'next_storage_num' => $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => $value['serial_info'],
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];

                    foreach($serialInfo as $val) {
                        $serialData[] = [
                            'storage_manage_id' => $storageManageId,
                            'batch_no' => '',
                            'serial_no' => $val,
                            'goods_id' => $value['type_id'],
                            'created_at' => time(),
                            'main_id' => $data['main_id'],
                        ];
                    }

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num']
                    );
                }
                else {
                    $existStorageData[] = [
                        'id' => $checkStorageManageInfo['id'],
                        'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                        'in_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num'] + $checkStorageManageInfo['in_storage_num'],
                    );

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $checkStorageManageInfo['id'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => $checkStorageManageInfo['in_storage_num'],
                        'next_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => $value['serial_info'],
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];
                }
            }
            else {
                if(empty($checkStorageManageInfo)) {
                    $storageManageId = StorageManageModel::insertGetId([
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'in_storage_num' => $value['num'],
                        'virtual_storage_num' => $value['num'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ]);

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $storageManageId,
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => 0,
                        'next_storage_num' => $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => '',
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num']
                    );
                }
                else {
                    $existStorageData[] = [
                        'id' => $checkStorageManageInfo['id'],
                        'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                        'in_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num'] + $checkStorageManageInfo['in_storage_num'],
                    );

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $checkStorageManageInfo['id'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => $checkStorageManageInfo['in_storage_num'],
                        'next_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => '',
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];
                }
            }
        }

        if(!empty($existStorageData)) {
            batch()->update(new StorageManageModel, $existStorageData, 'id');
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($serialData)) {
            SerialNumberModel::insert($serialData);
        }

        if(!empty($slaveData)) {
            batch()->update(new ProductSlaveModel, $slaveData, 'id');
        }

        return true;
    }

    //套件返仓
    private static function piecesInStorage(array $data, $productInfo)
    {
        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'main_id' => $data['main_id'],
            'delete_flag' => 0
        ])->first();

        if(empty($storageInfo)) {
            return ['code' => 1, 'msg' => '仓库不存在', 'data' => ''];
        }

        if($data['use_shelf']) {
            if($data['location_id'] == 0) {
                throw new Exception('设置中已开启货架，请选择货架库位后重试');
            }

            $shelfId = $data['shelf_id'];
            $locationId = $data['location_id'];
        }
        else {
            $shelfInfo = StorageShelfModel::where('storage_id', $data['storage_id'])->where('shelf_type', 1)->first();
            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])->first();

            $shelfId = $shelfInfo['id'];
            $locationId = $locationInfo['id'];
        }

        if(empty($data['materiel_content'])) {
            throw new Exception('请选择要入库的生产任务');
        }

        $materielContent = json_decode($data['materiel_content'], true);

        $slaveData = [];
        $logData = [];
        $existStorageData = [];
        $serialInfo = [];
        $slaveDataWithSerial = [];
        foreach($materielContent as $value) {
            $slaveContentInfo = ProductSlaveContentModel::where('id', $value['id'])->first();
            //检查库存是否存在
            $checkStorageManageInfo = StorageManageModel::getInfos([
                'type_id' => $value['type_id'],
                'storage_id' => $data['storage_id'],
                'main_id' => $data['main_id'],
                'shelf_id' => $shelfId,
                'location_id' => $locationId
            ]);

            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            if(!empty($value['serial_info'])) {
                $serialInfo = explode(',', $value['serial_info']);

//                //验证本次入库填写的序列号数量是否与入库数量相符
                if($value['num'] > count($serialInfo) || $value['num'] < count($serialInfo)) {
                    throw new Exception('您所填写的序列号数量与要入库的商品数不符，请重新填写');
                }

                $getSerialInfo = SerialNumberModel::whereIn('id', $serialInfo)->get()->toArray();

                $serialNumber = '';
                foreach($getSerialInfo as $val) {
                    $serialNumber .= $val['serial_no'].',';
                }

                $serialNumber = substr($serialNumber, 0, -1);

                $slaveDataWithSerial[] = [
                    'type_id' => $value['type_id'],
                    'serial_info' => $serialInfo
                ];

                if(empty($checkStorageManageInfo)) {
                    $storageManageId = StorageManageModel::insertGetId([
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'in_storage_num' => $value['num'],
                        'virtual_storage_num' => $value['num'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ]);

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $storageManageId,
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => 0,
                        'next_storage_num' => $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => $serialNumber,
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];

                    foreach($serialInfo as $val) {
                        $serialData[] = [
                            'storage_manage_id' => $storageManageId,
                            'batch_no' => '',
                            'serial_no' => $val,
                            'goods_id' => $value['type_id'],
                            'created_at' => time()
                        ];
                    }

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num']
                    );
                }
                else {
                    $existStorageData[] = [
                        'id' => $checkStorageManageInfo['id'],
                        'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                        'in_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num'] + $checkStorageManageInfo['in_storage_num'],
                    );

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $checkStorageManageInfo['id'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => $checkStorageManageInfo['in_storage_num'],
                        'next_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => $serialNumber,
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];
                }
            }
            else {
                if($value['num'] > ($slaveContentInfo['num'] - $slaveContentInfo['storage_operate_num'])) {
                    throw new Exception('超出可入库数量,当前可入库数量为'.($slaveContentInfo['num'] - $slaveContentInfo['storage_operate_num']));
                }

                $slaveData[] = [
                    'id' => $value['id'],
                    'storage_operate_num' => $slaveContentInfo['storage_operate_num'] + $value['num'],
                ];

                $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

                if(empty($checkStorageManageInfo)) {
                    $storageManageId = StorageManageModel::insertGetId([
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'in_storage_num' => $value['num'],
                        'virtual_storage_num' => $value['num'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ]);

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $storageManageId,
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => 0,
                        'next_storage_num' => $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => '',
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num']
                    );
                }
                else {
                    $existStorageData[] = [
                        'id' => $checkStorageManageInfo['id'],
                        'virtual_storage_num' => $checkStorageManageInfo['virtual_storage_num'] + $value['num'],
                        'in_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                    ];

                    MessageService::sendInSms(
                        '',
                        $materielTypeInfo['materiel_name'],
                        $materielTypeInfo['type_name'],
                        $data['storage_id'],
                        $storageInfo['storage_name'],
                        $data['user_id'],
                        $value['num'],
                        $value['num'] + $checkStorageManageInfo['in_storage_num'],
                    );

                    $logData[] = [
                        'type' => 0,
                        'curr_storage_manage_id' => $checkStorageManageInfo['id'],
                        'storage_id' => $data['storage_id'],
                        'storage_name' => $storageInfo['storage_name'],
                        'storage_address' => $storageInfo['storage_address'],
                        'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
                        'materiel_class_name' => $materielTypeInfo['sec_class_name'],
                        'materiel_class_no' => $materielTypeInfo['sec_class_no'],
                        'materiel_type_id' => $materielTypeInfo['id'],
                        'materiel_name' => $materielTypeInfo['materiel_name'],
                        'type_name' => $materielTypeInfo['type_name'],
                        'materiel_no' => $materielTypeInfo['materiel_no'],
                        'purchase_no' => '',
                        'operate_num' => $value['num'],
                        'last_storage_num' => $checkStorageManageInfo['in_storage_num'],
                        'next_storage_num' => $checkStorageManageInfo['in_storage_num'] + $value['num'],
                        'materiel_mean_cost' => $materielTypeInfo['cost'],
                        'serial_number' => '',
                        'all_id_type' => 4,
                        'all_id' => $data['id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'in_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $shelfId,
                        'location_id' => $locationId
                    ];
                }
            }
        }

        if(!empty($serialInfo)) {
            SerialNumberModel::whereIn('id', $serialInfo)->update(['status' => 1]);
        }

        if(!empty($logData)) {
            LogInStorageModel::insert($logData);
        }

        if(!empty($existStorageData)) {
            batch()->update(new StorageManageModel, $existStorageData, 'id');
        }

        if(!empty($slaveDataWithSerial)) {
            foreach($slaveDataWithSerial as $vals) {
                ProductSlaveContentModel::where('type_id', $vals['type_id'])
                    ->whereIn('serial_id', $vals['serial_info'])->update([
                        'storage_operate_num' => 1
                    ]);
            }
        }

        return true;
    }

    //出库-针对销售单生产任务出库
    private static function productOutStorage($data, $productInfo)
    {
        $content = json_decode($data['task_content'], true);
    }

    private static function productOutStorage1($data, $productInfo)
    {
        $content = json_decode($data['task_content'], true);

        $slaveContent = [];
        $outStorageData = [];
        $serialData = [];
        $logData = [];
        $sellData = [];
        foreach($content as $value) {
            $slaveInfo = ProductSlaveContentModel::where('id', $value['id'])->first();

            if($value['num'] > ($slaveInfo['num'] - $slaveInfo['storage_operate_num'])) {
                throw new Exception('超出可出库数量，当前可出库数量为:'.($slaveInfo['num'] - $slaveInfo['storage_operate_num']));
            }

            $slaveContent[] = [
                'id' => $value['id'],
                'storage_operate_num' => $slaveInfo['storage_operate_num'] + $value['num']
            ];

            $materielTypeInfo = MaterielTypeModel::getMainInfo($value['type_id']);

            if($materielTypeInfo['is_use_serial']) {
                if(empty($value['serial_info'])) {
                    throw new Exception('请选择序列号');
                }

                if(count($value['serial_info']) > $value['num'] || count($value['serial_info']) < $value['num']) {
                    throw new Exception('所需序列号数量与商品数量不符，请检查后重试');
                }

                foreach($value['serial_info'] as $serialContent) {
                    $arr['id'] = $serialContent['storage_manage_id'];
                    $storageManageInfo = StorageManageModel::detail($arr);

                    if(empty($storageManageInfo)) {
                        throw new Exception('库存信息不存在，请重试');
                    }

                    if($storageManageInfo['virtual_storage_num'] < 1) {
                        throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数不足');
                    }

                    if($storageManageInfo['in_storage_num'] < 1) {
                        throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'剩余库存数不足');
                    }

                    $serialInfo = SerialNumberModel::where('id', $serialContent['id'])->first();

                    if(empty($serialInfo)) {
                        throw new Exception('序列号不存在，请重试');
                    }

                    if(!$serialInfo['status']) {
                        throw new Exception('序列号:'.$serialInfo['serial_no'].'或已被使用，无法再次使用');
                    }

                    $outStorageData[] = [
                        'id' => $storageManageInfo['id'],
                        'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - 1,
                        'in_storage_num' => $storageManageInfo['in_storage_num'] - 1,
                    ];

                    $serialData[] = [
                        'id' => $serialInfo['id'],
                        'status' => 0
                    ];

                    $logData[] = [
                        'type' => 0,
                        'storage_id' => $storageManageInfo['storage_id'],
                        'storage_name' => $storageManageInfo['storage_name'],
                        'storage_address' => $storageManageInfo['storage_address'],
                        'curr_storage_manage_id' => $storageManageInfo['id'],
                        'materiel_class_id' => $storageManageInfo['s_class_id'],
                        'materiel_class_name' => $storageManageInfo['s_class_name'],
                        'materiel_class_no' => $storageManageInfo['s_class_no'],
                        'materiel_type_id' => $storageManageInfo['type_id'],
                        'materiel_name' => $storageManageInfo['materiel_name'],
                        'type_name' => $storageManageInfo['type_name'],
                        'materiel_no' => $storageManageInfo['materiel_no'],
                        'relation_code' => '',
                        'operate_num' => 1,
                        'serial_number' => $serialInfo['serial_no'],
                        'last_storage_num' => $storageManageInfo['in_storage_num'],
                        'next_storage_num' => $storageManageInfo['in_storage_num'] - 1,
                        'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
                        'fact_out_time' => strtotime(date('Y-m-d')),
                        'all_id_type' => 2,
                        'all_id' => $productInfo['product_source_id'],
                        'user_id' => $data['user_id'],
                        'main_id' => $data['main_id'],
                        'out_storage_time' => time(),
                        'created_at' => time(),
                        'shelf_id' => $storageManageInfo['shelf_id'],
                        'location_id' => $storageManageInfo['location_id'],
                    ];

                    MessageService::sendAlertSms(
                        $storageManageInfo['materiel_name'],
                        $storageManageInfo['type_name'],
                        $storageManageInfo['in_storage_num'],
                        $storageManageInfo['alert_num'],
                        $data['main_id'],
                        $storageManageInfo['storage_id'],
                        $storageManageInfo['storage_name'],
                        $value['num']
                    );

                    MessageService::sendShortSms(
                        $storageManageInfo['materiel_name'],
                        $storageManageInfo['type_name'],
                        $storageManageInfo['in_storage_num'],
                        $data['main_id'],
                        $storageManageInfo['storage_name'],
                        $storageManageInfo['storage_id'],
                    );

                    MessageService::sendOutSms(
                        $storageManageInfo['materiel_name'],
                        $storageManageInfo['type_name'],
                        $storageManageInfo['in_storage_num'],
                        $storageManageInfo['storage_name'],
                        $value['num'],
                        $data['user_id'],
                        $storageManageInfo['storage_id'],
                        $storageManageInfo['alert_num'],
                    );
                }
            }
            else {
                $arr['id'] = $serialContent['storage_manage_id'];
                $storageManageInfo = StorageManageModel::detail($arr);

                if(empty($storageManageInfo)) {
                    throw new Exception('库存信息不存在，请重试');
                }

                if($storageManageInfo['virtual_storage_num'] < 1) {
                    throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'可用库存数不足');
                }

                if($storageManageInfo['in_storage_num'] < 1) {
                    throw new Exception('库存商品'.$storageManageInfo['materiel_name'].'-'.$storageManageInfo['type_name'].'剩余库存数不足');
                }

                $outStorageData[] = [
                    'id' => $storageManageInfo['id'],
                    'virtual_storage_num' => $storageManageInfo['virtual_storage_num'] - $value['num'],
                    'in_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                ];

                $logData[] = [
                    'type' => 0,
                    'storage_id' => $storageManageInfo['storage_id'],
                    'storage_name' => $storageManageInfo['storage_name'],
                    'storage_address' => $storageManageInfo['storage_address'],
                    'curr_storage_manage_id' => $storageManageInfo['id'],
                    'materiel_class_id' => $storageManageInfo['s_class_id'],
                    'materiel_class_name' => $storageManageInfo['s_class_name'],
                    'materiel_class_no' => $storageManageInfo['s_class_no'],
                    'materiel_type_id' => $storageManageInfo['type_id'],
                    'materiel_name' => $storageManageInfo['materiel_name'],
                    'type_name' => $storageManageInfo['type_name'],
                    'materiel_no' => $storageManageInfo['materiel_no'],
                    'relation_code' => '',
                    'operate_num' => $value['num'],
                    'serial_number' => '',
                    'last_storage_num' => $storageManageInfo['in_storage_num'],
                    'next_storage_num' => $storageManageInfo['in_storage_num'] - $value['num'],
                    'materiel_mean_cost' => $storageManageInfo['materiel_mean_cost'],
                    'fact_out_time' => strtotime(date('Y-m-d')),
                    'all_id_type' => 2,
                    'all_id' => $productInfo['product_source_id'],
                    'user_id' => $data['user_id'],
                    'main_id' => $data['main_id'],
                    'out_storage_time' => time(),
                    'created_at' => time(),
                    'shelf_id' => $storageManageInfo['shelf_id'],
                    'location_id' => $storageManageInfo['location_id'],
                ];

                MessageService::sendAlertSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $storageManageInfo['alert_num'],
                    $data['main_id'],
                    $storageManageInfo['storage_id'],
                    $storageManageInfo['storage_name'],
                    $value['num']
                );

                MessageService::sendShortSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $data['main_id'],
                    $storageManageInfo['storage_name'],
                    $storageManageInfo['storage_id'],
                );

                MessageService::sendOutSms(
                    $storageManageInfo['materiel_name'],
                    $storageManageInfo['type_name'],
                    $storageManageInfo['in_storage_num'],
                    $storageManageInfo['storage_name'],
                    $value['num'],
                    $data['user_id'],
                    $storageManageInfo['storage_id'],
                    $storageManageInfo['alert_num'],
                );
            }

            $sellContentInfo = SellGoodsDetailModel::where([
                'sell_id' => $productInfo['product_source_id'],
                'type_id' => $value['type_id']
            ])->first();

            $sellData[] = [
                'id' => $sellContentInfo['id'],
                'out_num' => $sellContentInfo['out_num'] + $value['num']
            ];
        }

        if(!empty($outStorageData)) {
            batch()->update(new StorageManageModel, $outStorageData, 'id');
        }

        if(!empty($logData)) {
            LogOutStorageModel::insert($logData);
        }

        if(!empty($serialData)) {
            batch()->update(new SerialNumberModel, $serialData, 'id');
        }

        if(!empty($slaveContent)) {
            batch()->update(new ProductSlaveModel, $slaveContent, 'id');
        }

        if(!empty($sellData)) {
            batch()->update(new SellGoodsDetailModel, $sellData, 'id');
        }

        return true;
    }
}
